package edu.northwestern.cbits.purple_robot_manager.triggers;
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import edu.northwestern.cbits.purple_robot_manager.R;
import edu.northwestern.cbits.purple_robot_manager.activities.CodeViewerActivity;
import edu.northwestern.cbits.purple_robot_manager.logging.LogManager;
import edu.northwestern.cbits.purple_robot_manager.scripting.BaseScriptEngine;
public abstract class Trigger
{
public static final String NAME = "name";
public static final String ACTION = "action";
public static final String IDENTIFIER = "identifier";
private static final String ENABLED = "enabled";
private static final String LAST_FIRED = "last_fired";
public static final String TYPE = "trigger_type";
private String _name = null;
private String _action = null;
private String _identifier = "unidentified-trigger";
public Trigger(Context context, Map<String, Object> map)
{
this.updateFromMap(context, map);
}
public abstract boolean matches(Context context, Object obj);
public abstract void refresh(Context context);
public boolean enabled(Context context)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean(this.enabledKey(), true);
}
public void setEnabled(Context context, boolean enabled)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Editor e = prefs.edit();
e.putBoolean(this.enabledKey(), enabled);
e.commit();
}
public void execute(final Context context, boolean force)
{
if (this.enabled(context) && this._action != null)
{
final Trigger me = this;
Runnable r = new Runnable()
{
@Override
public void run()
{
try
{
BaseScriptEngine.runScript(context, me._action);
}
catch (Exception e)
{
LogManager.getInstance(context).logException(e);
HashMap<String, Object> payload = new HashMap<>();
payload.put("script", me._action);
LogManager.getInstance(context).log("failed_trigger_script", payload);
}
}
};
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String key = "last_fired_" + this.identifier();
Editor edit = prefs.edit();
edit.putLong(key, System.currentTimeMillis());
edit.commit();
Thread t = new Thread(new ThreadGroup("Triggers"), r, this.name(), 32768);
t.start();
HashMap<String, Object> payload = new HashMap<>();
payload.put("name", this.name());
payload.put("identifier", this.identifier());
payload.put("action", this._action);
LogManager.getInstance(context).log("pr_trigger_fired", payload);
}
}
@Override
public String toString()
{
return this.name();
}
public String name()
{
return this._name;
}
@Override
public boolean equals(Object obj)
{
if (obj != null && obj instanceof Trigger)
{
Trigger t = (Trigger) obj;
if ((t._identifier == null || this._identifier == null) && (t._name != null && t._name.equals(this._name)))
return true;
else if (t._identifier != null && t._identifier.equals(this._identifier))
return true;
}
return false;
}
public void merge(Trigger trigger)
{
this._name = trigger._name;
this._action = trigger._action;
}
public String identifier()
{
return this._identifier;
}
public void reset(Context context)
{
// Default implementation does nothing...
}
@SuppressWarnings("deprecation")
public PreferenceScreen preferenceScreen(final Context context, PreferenceManager manager)
{
PreferenceScreen screen = manager.createPreferenceScreen(context);
screen.setTitle(this._name);
String type = context.getString(R.string.type_trigger_unknown);
if (this instanceof ProbeTrigger)
type = context.getString(R.string.type_trigger_probe);
if (this instanceof DateTrigger)
type = context.getString(R.string.type_trigger_datetime);
if (this instanceof BatteryLevelTrigger)
type = context.getString(R.string.type_trigger_battery);
screen.setSummary(type);
final Trigger me = this;
Preference viewAction = new Preference(context);
viewAction.setTitle(R.string.label_trigger_show_action);
viewAction.setSummary(R.string.label_trigger_show_action_desc);
viewAction.setOrder(Integer.MAX_VALUE);
viewAction.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = new Intent(context, CodeViewerActivity.class);
intent.putExtra(CodeViewerActivity.SOURCE_CODE, me._action);
intent.putExtra(CodeViewerActivity.TITLE, me.name());
context.startActivity(intent);
return true;
}
});
screen.addPreference(viewAction);
CheckBoxPreference enabled = new CheckBoxPreference(context);
enabled.setTitle(R.string.label_trigger_enable_action);
enabled.setSummary(R.string.label_trigger_enable_action_desc);
enabled.setKey(this.enabledKey());
enabled.setDefaultValue(true);
enabled.setOrder(Integer.MAX_VALUE);
enabled.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
return true;
}
});
screen.addPreference(enabled);
this.addCustomPreferences(context, screen);
Preference fireNow = new Preference(context);
fireNow.setTitle(R.string.label_trigger_fire_now);
fireNow.setSummary(R.string.label_trigger_fire_now_desc);
fireNow.setOrder(Integer.MAX_VALUE / 2);
fireNow.setOnPreferenceClickListener(new OnPreferenceClickListener()
{
@Override
public boolean onPreferenceClick(Preference preference)
{
me.execute(context, true);
return true;
}
});
screen.addPreference(fireNow);
return screen;
}
public void addCustomPreferences(Context context, PreferenceScreen screen) {
// Do nothing by default...
}
private String enabledKey()
{
return "trigger_enabled_" + this._identifier;
}
public static Trigger parse(Context context, Map<String, Object> params)
{
String type = params.get("type").toString();
if (DateTrigger.TYPE_NAME.equals(type))
return new DateTrigger(context, params);
else if (ProbeTrigger.TYPE_NAME.equals(type))
return new ProbeTrigger(context, params);
else if (BatteryLevelTrigger.TYPE_NAME.equals(type))
return new BatteryLevelTrigger(context, params);
return null;
}
public Map<String, Object> configuration(Context context)
{
Map<String, Object> config = new HashMap<>();
config.put("name", this._name);
if (this._identifier != null)
config.put("identifier", this._identifier);
else
config.put("identifier", "unspecified-identifier");
if (this._action != null)
config.put("action", this._action);
else
config.put("action", "");
if (this._name != null)
config.put("name", this._name);
else
config.put("name", context.getString(R.string.name_anonymous_trigger));
return config;
}
public boolean updateFromMap(Context context, Map<String, Object> params)
{
if (params.containsKey("name"))
this._name = params.get("name").toString();
if (params.containsKey("action"))
this._action = params.get("action").toString();
if (params.containsKey("identifier"))
{
try
{
this._identifier = params.get("identifier").toString();
}
catch (NullPointerException e)
{
this._identifier = "unspecified-identifier";
}
}
TriggerManager.getInstance(context).persistTriggers(context);
return true;
}
public abstract String getDiagnosticString(Context context);
public Bundle bundle(Context context)
{
Bundle bundle = new Bundle();
bundle.putString(Trigger.NAME, this._name);
if (this._action != null)
bundle.putString(Trigger.ACTION, this._action);
bundle.putString(Trigger.IDENTIFIER, this._identifier);
bundle.putBoolean(Trigger.ENABLED, this.enabled(context));
bundle.putLong(Trigger.LAST_FIRED, this.lastFireTime(context));
return bundle;
}
public long lastFireTime(Context context)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String key = "last_fired_" + this.identifier();
return prefs.getLong(key, 0);
}
}